package com.weixing.mall.pay.channel.wx;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.weixing.mall.pay.IPayment;
import com.weixing.mall.pay.PayParam;
import com.weixing.mall.pay.PayResult;
import com.weixing.mall.pay.QueryResult;
import com.weixing.mall.pay.channel.wx.sdk.WXPay;
import com.weixing.mall.pay.enums.TradeTypeEnum;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName AbstractWxPay
 * @Description
 * @Author Small
 * @Date 2019/11/28 9:44
 * @Version 1.0
 **/
@Slf4j
public abstract class AbstractWxPay implements IPayment {
    protected static final String SUCCESS = "SUCCESS";
    protected static final String FAIL = "FAIL";
    protected static final String RESULT_CODE = "resultCode";
    protected static final String RESULT_MSG = "resultMsg";
    protected static final String TRADE_STATE = "tradeState";
    protected static final String TRADE_STATE_MSG = "tradeStateDesp";

    protected WxPayConfigImpl wxPayConfig;


    public AbstractWxPay(WxPaySet wxPaySet) {
        this.wxPayConfig = initWxPayConfig(wxPaySet);
    }

    public AbstractWxPay(WxPaySet wxPaySet, WxTradeTypeEnum tradeType) {
        this.wxPayConfig = initWxPayConfig(wxPaySet,tradeType);
    }


    WxPayConfigImpl initWxPayConfig(WxPaySet wxPaySet) {
        WxPayConfigImpl instance = WxPayConfigImpl.getInstance();
        instance.setContext(wxPaySet);
        return instance;
    }


    WxPayConfigImpl initWxPayConfig(WxPaySet wxPaySet,WxTradeTypeEnum tradeType) {
        WxPayConfigImpl instance = WxPayConfigImpl.getInstance();
        instance.setContext(wxPaySet);
        instance.setTradeType(tradeType);
        return instance;
    }


    protected WXPay initWxPay() {

        WxPaySet context = wxPayConfig.getContext();
        WXPay wxpay = null;

        try {
            wxpay = new WXPay(wxPayConfig, context.getNotifyUrl(), context.isAutoReport(), context.isUseSandbox());
        } catch (Exception e) {
            log.warn("初始化WxPay异常", e);
        }
        return wxpay;
    }

    /**
     * 方法描述: 统一下单接口
     * @Author Small
     * @param payParam
     * @Date 2019/11/29 17:41
     * @return com.weixing.mall.pay.PayResult
     */
    @Override
    public abstract PayResult pay(PayParam payParam);

    public abstract boolean needOpenId();


    /**
     * 方法描述: 封装支付请求参数
     * @Author Small
     * @param payParam
     * @Date 2019/11/29 10:01
     * @return java.util.HashMap<java.lang.String, java.lang.String>
     */
    protected HashMap<String, String> wapperRequestData(PayParam payParam, String tradeType) {
        HashMap<String, String> data = new HashMap<String, String>(8);
        // 商品描述
        data.put("body", payParam.getBody());
        // 商户订单号
        data.put("out_trade_no", payParam.getOutTransNo());
        // 币种
        data.put("fee_type", "CNY");
        // 支付金额
        String amount = String.valueOf(NumberUtil.mul(payParam.getAmount(), 100).intValue());
        data.put("total_fee", amount);
        // 乘客终端IP
        data.put("spbill_create_ip", payParam.getRemoteIp());
        data.put("spbill_create_ip", "223.104.11.207");
        // 交易类型
        data.put("trade_type", tradeType);
        // 用户标识
        if (needOpenId()) {
            data.put("openid", payParam.getOpenid());
        }

        System.out.println(JSON.toJSONString(data));
        return data;
    }

    /**
     * 方法描述: 解析支付返回参数
     * @Author Small
     * @param r
     * @Date 2019/11/28 18:18
     * @return java.util.Map<java.lang.String, java.lang.String>
     */
    protected final Map<String, String> parseResponse(Map<String, String> r) {
        String returnCode = r.get("return_code");
        String returnMsg = r.get("return_msg");
        String resultCode = returnCode;
        String resultMsg = returnMsg;
        if (SUCCESS.equals(returnCode)) {
            String payResultCode = r.get("result_code");
            if (!SUCCESS.equals(payResultCode)) {
                resultCode = r.get("err_code");
                resultMsg = r.get("err_code_des");
            }
        }
        Map<String, String> resultMap = new HashMap<>(2);
        resultMap.put(RESULT_CODE, resultCode);
        resultMap.put(RESULT_MSG, resultMsg);
        return resultMap;
    }

    /**
     * 方法描述: 解析查询返回参数
     * @Author Small
     * @param r
     * @Date 2019/11/28 18:18
     * @return java.util.Map<java.lang.String, java.lang.String>
     */
    protected final Map<String, String> parseQueryResponse(Map<String, String> r) {
        String returnCode = r.get("return_code");
        String returnMsg = r.get("return_msg");
        String resultCode = returnCode;
        String resultMsg = returnMsg;
        String tradeState = null;
        String tradeStateMsg = null;
        // 通信成功
        if (SUCCESS.equals(returnCode)) {
            String payResultCode = r.get("result_code");
            // 业务查询成功
            if (SUCCESS.equals(payResultCode)) {
                // 交易状态
                tradeState = r.get("trade_state");
                tradeStateMsg = r.get("trade_state_desc");
            } else {
                resultCode = r.get("err_code");
                resultMsg = r.get("err_code_des");
            }
        }
        Map<String, String> resultMap = new HashMap<>(4);
        resultMap.put(RESULT_CODE, resultCode);
        resultMap.put(RESULT_MSG, resultMsg);
        resultMap.put(TRADE_STATE, tradeState);
        resultMap.put(TRADE_STATE_MSG, tradeStateMsg);
        return resultMap;
    }

    /**
     * 方法描述: 订单查询
     * @Author Small
     * @param outTransNo  平台订单号
     * @Date 2019/11/29 19:57
     * @return java.util.Map<java.lang.String, java.lang.Object>
     */
    @Override
    public final QueryResult query(String outTransNo) {
        log.info("WxQuery=>订单{} 请求到达", outTransNo);
        try {
            // 查询订单状态
            Map<String, String> map = new HashMap<>();
            map.put("out_trade_no", outTransNo);
            WxPayConfigImpl payConfig = WxPayConfigImpl.getInstance();
            WxPaySet context = payConfig.getContext();
            WXPay wxpay = new WXPay(payConfig, context.getNotifyUrl(), context.isAutoReport(), context.isUseSandbox());
            Map<String, String> r = wxpay.orderQuery(map);
            log.info("WxQuery=>订单{} 返回报文，{}", outTransNo, r);
            Map<String, String> queryResponse = parseQueryResponse(r);
            String resultCode = queryResponse.get(RESULT_CODE);
            String resultMsg = queryResponse.get(RESULT_MSG);
            String tradeState = queryResponse.get(TRADE_STATE);
            if (SUCCESS.equals(resultCode)) {
                boolean valid = wxpay.isResponseSignatureValid(r);
                if (!valid) {
                    log.warn("WxQuery=>订单{} 验签失败", outTransNo);
                    return QueryResult.invalidSign();
                } else {
                    if (TradeStateEnum.SUCCESS.getStatus().equals(tradeState)) {
                        String tradeNo = r.get("transaction_id");
                        return QueryResult.tradeSuccess(tradeNo);
                    } else {
                        String trade_state_desc = r.get("trade_state_desc");
                        return QueryResult.tradeNotSuccess(tradeState, trade_state_desc);
                    }
                }
            } else {
                log.info("WxQuery=>订单{} 查询失败,错误代码{},错误原因{}", outTransNo, resultCode, resultMsg);
                return QueryResult.fail(resultCode, resultMsg);
            }
        } catch (Exception e) {
            log.warn("WxQuery=>订单{} 查询时发生异常", outTransNo, e);
        }
        return QueryResult.unknowException();
    }


}
